/**
 * 
 */
package will.icecoffe.core;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import will.icecoffe.utils.Page;

/**
 * @author Will.E
 * 
 */
/**
 * @author will
 *
 */
@Component("basicDao")
public class BasicDAO extends HibernateDaoSupport implements DataAccessObject {

	/**
	 * SessionFactory 注入入口，通常情况下无需管理。
	 * @param sessionFactory
	 */
	@Resource(name = "sessionFactory")
	public void setBaseDaoSessionFactory(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#save(java.lang.Object)
	 */
	@Override
	@Transactional(rollbackFor=DataAccessException.class)
	public void save(final Object obj) throws DataAccessException {
		getHibernateTemplate().save(obj);
		//throw new DataAccessException("ss");
		//return obj;
		/*
		return getHibernateTemplate().execute(new HibernateCallback() {

			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				//session.connection().setAutoCommit(false);
				session.beginTransaction();
				session.save(obj);
				//session.connection().commit();
				return obj;
			}
		});
		//*/
	}

	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#update(java.lang.Object)
	 */
	@Override
	@Transactional
	public void update(Object obj) throws DataAccessException {
		try {
			getHibernateTemplate().update(obj);
		} catch(Exception e) {
			
		}
	}
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#saveOrUpdate(java.lang.Object)
	 */
	@Override
	@Transactional
	public void saveOrUpdate(Object obj) throws DataAccessException {
		try {
			getHibernateTemplate().saveOrUpdate(obj);
		} catch (Exception e) {

		}
	}

	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#delete(java.lang.Object)
	 */
	@Override
	@Transactional
	public void delete(Object obj) throws DataAccessException {
		try {
			getHibernateTemplate().delete(obj);
		} catch (Exception e) {

		}
	}

	
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#find(java.lang.Object)
	 */
	@Override
	@Transactional
	public List<Object> find(Object obj) throws DataAccessException {
		try {
			return getHibernateTemplate().findByExample(obj);
		} catch (Exception e) {

		}
		
		return null;
	}
	
	
	
	
	/*
	 * 分页查询方法,提供对命名HQL查询的分页获取能力。
	 */
	
	//----------------------------------分页查询方法开始----------------------------------
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#findInPage(int, int, java.lang.String)
	 */
	@Override
	@Transactional
	public Page<Object> findBasedPage(final int pageNum, final int maxResult, final String queryName, final Object...params)
			throws DataAccessException {
		
		Page p = null;
		
		try {
			
			p = (Page) getHibernateTemplate().executeFind(new HibernateCallback() {
				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,
						SQLException {
					Query query = makeQuery(session, queryName, params);
					query.setFirstResult((pageNum - 1) * maxResult);
					query.setMaxResults(maxResult);
					
					Page page = new Page(query.list());
					page.setCurrentPage(pageNum);
					page.setRecordPerPage(maxResult);
					page.setTotalRecords(getTotalPageNum(queryName));
					page.setTotalPages(page.getTotalRecords() % maxResult + 1);
					return page;
				}
			});
			
		} catch(QueryParametersException e) {
			throw new DataAccessException("Query Parameters is NOT matching!\n查询参数不匹配。");
		}
		
		return p;
	}
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#findInPage(int, int, java.lang.String)
	 */
	@Override
	@Transactional
	public Page<Object> findBasedPageNative(final int pageNum, final int maxResult, final String queryName, final Object...params)
			throws DataAccessException {
		
		Page p = null;
		
		try {
			
			p = (Page) getHibernateTemplate().executeFind(new HibernateCallback() {
				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,
				SQLException {
					SQLQuery query = (SQLQuery) makeNativeQuery(session, queryName, params);
					query.setFirstResult((pageNum - 1) * maxResult);
					query.setMaxResults(maxResult);
					
					Page page = new Page(query.list());
					page.setCurrentPage(pageNum);
					page.setRecordPerPage(maxResult);
					page.setTotalRecords(getTotalPageNumNative(queryName));
					page.setTotalPages(page.getTotalRecords() % maxResult + 1);
					return page;
				}
			});
			
		} catch(QueryParametersException e) {
			throw new DataAccessException("Query Parameters is NOT matching!\n查询参数不匹配。");
		}
		
		return p;
	}

	
	/**
	 * HQL翻页辅助方法，用于计算总页码。
	 * 
	 * @return
	 */
	private int getTotalPageNum() {
		
		return 0;
	}
	
	/**
	 * HQL翻页辅助方法，用于计算总页码。
	 * 
	 * @return
	 */
	private int getTotalPageNumNative() {
		
		return 0;
	}
	
	/**
	 * HQL翻页辅助方法，用于计算总页码。
	 * 
	 * @return
	 */
	private int getTotalPageNum(String queryName) {
		
		return ((Long) getHibernateTemplate().findByNamedQuery(queryName + "Count").get(0)).intValue();
	}
	
	/**
	 * HQL翻页辅助方法，用于计算总页码。
	 * 
	 * @return
	 */
	private int getTotalPageNumNative(final String queryName) {
		
		return ((Long) getHibernateTemplate().executeFind(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				SQLQuery query = (SQLQuery) makeNativeQuery(session, queryName + "Count", null);
				return query.list();
			}
		}).get(0)).intValue();
		
	}
	

	//----------------------------------HQL分页查询方法结束----------------------------------
	
	
	
	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#executeNamedHQLQuery(java.lang.String, java.lang.Object[])
	 */
	@Override
	@Transactional
	public List<Object> executeNamedHQLQuery(final String queryName, final Object...params)
			throws DataAccessException {
		
		List<Object> list = null;
		
		try {
		
			list = getHibernateTemplate().executeFind(new HibernateCallback() {
				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,
						SQLException {
					Query query = makeQuery(session, queryName, params);
					List<Object> t = query.list();
					return t;
				}
			});
			
		} catch(QueryParametersException e) {
			throw new DataAccessException("Query Parameters is NOT matching!\n查询参数不匹配。");
		}
		
		return list;
	}

	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#executeNamedHQL(java.lang.String, java.lang.Object[])
	 */
	@Override
	@Transactional
	public void executeNamedHQL(final String queryName, final Object...params) throws DataAccessException {

		try {
			
			getHibernateTemplate().execute(new HibernateCallback() {
				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,
						SQLException {
					Query query = makeQuery(session, queryName, params);
					return query.executeUpdate();
				}
			});
			
		} catch(QueryParametersException e) {
			throw new DataAccessException("Query Parameters is NOT matching!\n查询参数不匹配。");
		}
		
	}

	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#executeNamedSQLQuery(java.lang.String, java.lang.String, java.lang.Object[])
	 */
	@Override
	@Transactional
	public List<Object> executeNamedSQLQuery(final String queryName,
			 final Object...params) throws DataAccessException {
		List<Object> list = null;
		
		try {
		
			list = (List<Object>) getHibernateTemplate().execute(new HibernateCallback() {
				
				@Override
				public Object doInHibernate(Session session) throws HibernateException,
						SQLException {
					
					SQLQuery query = (SQLQuery) makeNativeQuery(session, queryName, params);
					return query.list();
					
				}
			});
			
		} catch(QueryParametersException e) {
			throw new DataAccessException("Query Parameters is NOT matching!\n查询参数不匹配。");
		}
		
		return list;
	}

	/* (non-Javadoc)
	 * @see will.icecoffe.core.DataAccessObject#executeNamedSQL(java.lang.String, java.lang.Object[])
	 */
	@Override
	@Transactional
	public void executeNamedSQL(final String queryName, final Object...params) throws DataAccessException {
		
		getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				
				Query query = makeNativeQuery(session, queryName, params);
				query.executeUpdate();
				
				return null;
			}
		});

	}

	
	
	@Override
	@Deprecated
	@Transactional
	public List<Object> executeHQLQuery(final String hql) throws DataAccessException {
		
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql);
				return query.list();
			}
		});

	}

	@Override
	@Deprecated
	@Transactional
	public void executeHQL(final String hql) throws DataAccessException {
		
		getHibernateTemplate().execute(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(hql);
				return query.executeUpdate();
			}
		});

	}

	@Override
	@Deprecated
	@Transactional
	public ResultSet executeSQLQuery(final String sql) throws DataAccessException {
		
		return (ResultSet) getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				return session.connection().createStatement().executeQuery(sql);
			}
		});
		
	}

	@Override
	@Deprecated
	@Transactional
	public void executeSQL(final String sql) throws DataAccessException {
		
		getHibernateTemplate().executeWithNativeSession(new HibernateCallback() {
			
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createSQLQuery(sql);
				return query.executeUpdate();
			}
		});

	}

	
	/**
	 * HQL查询生成器，用户组合语句与参数。
	 * 
	 * @param session
	 * @param queryName
	 * @param params
	 * 
	 * @return
	 * 
	 * @throws QueryParametersException
	 */
	private Query makeQuery(Session session, String queryName, Object...params) throws QueryParametersException {
		
		Query query = session.getNamedQuery(queryName);
		
		if(null != params && 0 != params.length)
			query = paramsSetter(query, params);
		
		return query;
		
	}
	
	/**
	 * SQL查询生成器，用户组合语句与参数。
	 * 
	 * @param session
	 * @param queryName
	 * @param resultSetMapping
	 * @param params
	 * @return
	 * @throws QueryParametersException
	 */
	private Query makeNativeQuery(Session session, String queryName, Object...params) throws QueryParametersException {
		
		SQLQuery query = (SQLQuery) session.getNamedQuery(queryName);
		
		if(null != params && 0 != params.length)
			query = (SQLQuery) paramsSetter(query, params);
		
		return query;
		
	}
	
	private Query paramsSetter(Query query, Object...params) throws QueryParametersException {
		
		if(null == params || params.length == 0) {
			throw new QueryParametersException("Paramers is Null");
			//return query;
		} else if(params.length == 1 && params[0] instanceof Map) {

			for(Map.Entry<String, Object> e : ((Map<String, Object>) params[0]).entrySet()) {
				query.setParameter(e.getKey(), e.getValue());
			}
			
		} else {
			
			for(int i = 0; i < params.length; ++i) {
				
				if(params[i] instanceof String)
					query.setString(i, (String) params[i]);
				else if(params[i] instanceof Integer)
					query.setInteger(i, (Integer) params[i]);
				else if(params[i] instanceof Float)
					query.setFloat(i, (Float) params[i]);
				else if(params[i] instanceof Double)
					query.setDouble(i, (Double) params[i]);
				else if(params[i] instanceof Long)
					query.setLong(i, (Long) params[i]);
				else if(params[i] instanceof Date)
					query.setDate(i, (Date) params[i]);
				else if(params[i] instanceof Timestamp)
					query.setTimestamp(i, (Timestamp) params[i]);
				else if(params[i] instanceof Character)
					query.setCharacter(i, (Character) params[i]);
				else if(params[i] instanceof Byte)
					query.setByte(i, (Byte) params[i]);
				else if(params[i] instanceof List) {
					query.setParameter(i, ((List) params[i]).toArray());
				} else
					throw new QueryParametersException("Query Parameters Type is NOT matching!\n查询参数类型“" + params[i].getClass().getName() + "”不支持。");
				
			}
		}
		
		return query;
	}
}
